
package Serveur;

import Client.I_ChatClient;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ServeurChat extends UnicastRemoteObject implements I_chat {
    
    private static final long serialVersionUID = 1L;
    //Nombre d'utilisateur maximum du serveur
    private int nb_utilisateur;
    //Taille maximale des fichier envoyés au serveur
    private int tailleFichier;
    //Liste des utilisateurs du chat
    public LinkedList <I_ChatClient> clients;
    //Stockage des fichiers sur le serveur ou String est l'auteur des fichiers
    private Hashtable<String, LinkedList <Fichier>> StockageFichier;
    //Historique des messages du chat 
    public ArrayList <String> history;
    //Fichier de log
    private File fichier;
        
    public ServeurChat(int nbClient, int taille) throws RemoteException {
        super();
        //Fixe le nombre d'utilisateur maximal du serveur
        setNb_utilisateur(nbClient);
        //Fixe la taille maximale des fichiers sur le serveur
        setTailleFichier(taille);
        //Créer le fichier de login
        creerFichLog();
        //Instancie la liste des utilisateurs du chat
        clients = new LinkedList<I_ChatClient>();
        //Instancie le stockage des fichiers
        StockageFichier = new Hashtable<String, LinkedList <Fichier>>();
        //Instancie l'historique du chat
        history = new ArrayList<String>();
    }
    
    @Override
        public synchronized void connecter(I_ChatClient client) throws RemoteException {            
            clients.add(client); 
            //Affiche l'historique des messages
            if (!history.isEmpty()) {
              for (int i = 0; i < history.size(); i++) {
                client.recevoir(history.get(i), "", 'h');  
              }  
            }
        }

        @Override
        public void deconnecter(String nomClient) throws RemoteException {
          
            int i;
            i=chercherNom(nomClient);
            clients.remove(i);
        }
        
    @Override
        public synchronized String envoyerMessage(String message, String auteur, char mode) throws RemoteException {
            String retour = null;
            //Mise à jour de l'historique des messages
            if (mode == 's') {
                history.add(auteur + " dit : " + message);
            }
            if (mode == 'h') {
                history.add(auteur +" "+ message);
            }
            //Envoi du message à tous les utilisateurs
            for (int i = 0; i < clients.size(); i++){
                    retour = clients.get(i).recevoir(message, auteur, mode);
            }
            return retour;
        }
    
    @Override
    public ArrayList<String> retourHistorique() throws RemoteException{
        return history;
    }
    
    @Override
        public LinkedList<I_ChatClient> clientsDisponibles() throws RemoteException{
            return this.clients;
        }
    
    @Override
        public void messagePrive(String message, String exp, String des, char mode) throws RemoteException{
            int i;
            i=chercherNom(des);
            String mess = clients.get(i).recevoir(message, exp, mode);
            history.add(mess);
        }
        
     @Override
        public int chercherNom(String nom) throws RemoteException{
            int res=-1;
            for(int j=0;j<clients.size();j++){
                if(clients.get(j).getNomClient().equals(nom)){
                    res=j;
                }
            }
            
            return res;
        }
        
        @Override
        public boolean utilisateurPasDejaPresent(String nom) throws RemoteException{
            boolean rep=true;
            for(int i=0;i<clients.size();i++){
                if(clients.get(i).getNomClient().equalsIgnoreCase(nom)){
                    rep=false;
                }
            }
            return rep;
        }

        @Override
        public boolean tailleFichierValide(File fichier) throws RemoteException{
            boolean valide = false;
            if(fichier.length()/1024 > getTailleFichier()){
                try {
                    throw new Exception("Fichier trop volumineux");
                } 
                catch (Exception ex) {
                    Logger.getLogger(ServeurChat.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            else{
                valide = true;
            }
            return valide;
        }

        @Override
        public void deposerFichier(String nomFichierAcreer, String path, String auteur) throws RemoteException {
            
            BufferedInputStream bis = null;
            byte[] buf;
            File nomFichier = new File(path);
            try {                    
                bis = new BufferedInputStream(new FileInputStream(nomFichier));
            } catch (FileNotFoundException ex) {
                Logger.getLogger(ServeurDrive.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            if(tailleFichierValide(nomFichier)) {
                
                buf = new byte[(int)nomFichier.length()];	
                    
                int ch;
                int i = 0;
                    
                try {			

                    FileInputStream f = new FileInputStream(nomFichier); 

                    try {
                        //Creation du tableau de bytes
                        while((ch = bis.read()) != -1) { 
                            buf[i] = (byte)ch;
                            i++;						
                        }
                        Fichier fic = new Fichier(nomFichierAcreer,buf);
                        LinkedList <Fichier> stockageAuteur = StockageFichier.get(auteur);
                        stockageAuteur.add(fic);
                        StockageFichier.put(auteur, stockageAuteur);
                    }

                    finally {
                            f.close();
                    }
                }

                    catch(FileNotFoundException f){
                        System.out.println("Le fichier est introuvable.");
                    }
                    catch(IOException e){
                        System.out.println(e + "Erreur lors de la lecture du fichier.");		
                    }
                try {
                    bis.close();
                } catch (IOException ex) {
                    Logger.getLogger(ServeurDrive.class.getName()).log(Level.SEVERE, null, ex);
                }
            }   
        }
        
        @Override
        public LinkedList <Fichier> consulterFichier(String auteur) throws RemoteException {
            return StockageFichier.get(auteur);
        }
        
        @Override
        public void partagerFichier(String destinataire, String nomFichier, String auteur) throws RemoteException {
            
            if(utilisateurPasDejaPresent(destinataire)) {
                Fichier fic = new Fichier(nomFichier, null);
                //Récupère l'index du fichier correspondant au nom que je recherche
                int index = StockageFichier.get(auteur).indexOf(fic.getNom());
                //Récupère le tableau de bytes correspondant au fichier que je recherche
                byte[] buf = StockageFichier.get(auteur).get(index).getData();
                
                fic.setData(buf);
                LinkedList <Fichier> stockageDestinataire = StockageFichier.get(destinataire);
                stockageDestinataire.add(fic);
                StockageFichier.put(destinataire, stockageDestinataire);
            }
        }
        
        
        @Override
        public void recomposerFichier(String path, String auteur, String nomFichier) throws RemoteException {
            try {
                BufferedOutputStream bos;
                
                bos = new BufferedOutputStream(new FileOutputStream(new File(path)));
                Fichier fic = new Fichier(nomFichier,null);
                //Récupère l'index du fichier correspondant au nom que je recherche
                int index = StockageFichier.get(auteur).indexOf(fic.getNom());
                //Récupère le tableau de bytes correspondant au fichier que je recherche
                byte[] buf = StockageFichier.get(auteur).get(index).getData();
                for (int i = 0 ; i < buf.length ; i++) {
                    bos.write((int)buf[i]);
                }	 
                System.out.println("Fichier crée.");
                bos.close();
            }
                    
	    catch(IOException e) {
                 System.out.println(e + "Erreur lors de la lecture du fichier.");
            }
        }
        
        /** Retourne la taille maximale des fichiers qu'on peut envoyer sur le serveur
         * @return la taille max des fichiers en ko
         */
        public int getTailleFichier() {
            return tailleFichier;
        }

        /** Affecte la taille maximale des fichiers qu'on peut envoyer sur le serveur
         * @param nb_utilisateur la taille max des fichiers en ko
         */
        public void setTailleFichier(int tailleFichier) {
            this.tailleFichier = tailleFichier /1024;
        }

        /** Retourne le nombre d'utilisateur maximum du serveur
         * @return le nombre d'utilisateur max
         */
        public int getNb_utilisateur() {
            return nb_utilisateur;
        }

        /** Affecte le nombre d'utilisateur maximum du serveur
         * @param nb_utilisateur le nombre d'utilisateur max
         */
        public void setNb_utilisateur(int nb_utilisateur) {
            this.nb_utilisateur = nb_utilisateur;
        }

    @Override
        //Fonction permettant de vérifier si le nom de l'utilisateur et son mot de passe sont correctes
        public boolean verifLogin(String nom, String motdPasse)throws RemoteException{
            boolean stop=false;
            boolean rep=false;
            BufferedReader br = null;
 
		try {
 
			String nomU,mdp;
 
			br = new BufferedReader(new FileReader("logs.txt"));
 
			while ((nomU = br.readLine()) != null && stop==false) {
				if(nomU.equals(nom)){
                                    mdp=br.readLine();
                                    if(mdp.equals(motdPasse)){
                                        rep=true;
                                    }
                                    stop=true;
                                }
			}
		} 
                catch (IOException e) {
			e.printStackTrace();
		} 
                finally {
			try {
				if (br != null)br.close();
			} 
                        catch (IOException ex) {
				ex.printStackTrace();
			}
		}
            return rep;
        }
        
        @Override
        public boolean verifUsername(String nom)throws RemoteException{
            boolean rep=false;
            BufferedReader br = null;
 
		try {
 
			String sCurrentLine;
 
			br = new BufferedReader(new FileReader("logs.txt"));
 
			while ((sCurrentLine = br.readLine()) != null && rep==false) {
				if(sCurrentLine.equals(nom)){
                                    rep=true;
                                    br.readLine();
                                }
			}
 
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (br != null)br.close();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
            return rep;
        }

    //Inscription
         @Override
         public void ajouterLog(String nomU,String mdp)throws RemoteException{
            FileWriter outFile = null;
            BufferedWriter bufferedWriter;
            try {
                bufferedWriter = new BufferedWriter(new FileWriter(this.fichier, true));
                bufferedWriter.write(nomU);
                bufferedWriter.newLine();
                bufferedWriter.write(mdp);
                bufferedWriter.newLine();
                bufferedWriter.close();
            } 
            catch (IOException ex) {
                Logger.getLogger(Serveur.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
         
         //Nouvelle méthode : Création d'un fichier contenant les noms d'utilisateur et les mot de passe
    @Override
        public void creerFichLog() throws RemoteException {
                File fichier = new File("logs.txt");
                if (fichier.exists()) {
                        System.out.println("Le fichier de log existe!");
                } else {
                try {
                    fichier.createNewFile();
                } catch (IOException ex) {
                    Logger.getLogger(Serveur.class.getName()).log(Level.SEVERE, null, ex);
                }
                        System.out.println("Le fichier de log a été créé !");
                }
                this.fichier=fichier;
        }
}
